function Promise(executor) {
  if (!(this instanceof Promise)) {
    return new Promise(executor)
  }
  this.status = 'pending';
  this.success = undefined;
  this.error = undefined;
  this.successAsync = [];
  this.errorAsync = [];


  const resolve = success => {
    if (this.status === 'pending') {
      this.success = success;
      this.successAsync.forEach(e => e())
      this.pending = 'resolved';
    }
  }

  const reject = err => {
    if (this.status === 'pending') {
      this.status = 'rejected';
      this.errorAsync.forEach(e => e())
      this.error =err;
    }
  }

  try {
    executor(resolve, reject)
  } catch (error) {
    reject(error)
  }
}

Promise.prototype.then = function(onResolved, onRejected) {
  const self = this;
  onResolved = typeof onResolved === 'function' ? onResolved : val => val;
  onRejected = typeof onRejected === 'function' ? onRejected : err => {
    throw err;
  };

  const promiseAgin = new Promise((resolve, reject) => {
    if (self.status === 'pending') {
      self.successAsync.push(() => {
        const x = onResolved(self.success);
        resolvePromise(promiseAgin, x, resolve, reject);
      })

      self.errorAsync.push(() => {
        const x = onRejected(self.error);
        resolvePromise(promiseAgin, x, resolve, reject);
      })

    }

    if (self.status === 'resolved') {
      try {
        const x = onResolved(self.success);
        resolvePromise(promiseAgin, x, resolve, reject);
      } catch (error) {
        reject(error)
      }
    }

    if (self.status === 'rejected') {
      try {
        const x = onRejected(self.error)
        resolvePromise(promiseAgin, x, resolve, reject)
      } catch (error) {
        reject(error)
      }
    }
  })
  return promiseAgin
}

function resolvePromise(promiseAgin, x, resolve, reject) {
  if (promiseAgin === x) {
    return reject(new TypeError('循环调用'))
  }

  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;
      if (typeof then === 'function') {
        then.call(x, y => {
          resolvePromise(promiseAgin, y, resolve, reject);
        }, e => {
          reject(e)
        })
      } else {
        resolve(x)
      }


    } catch (error) {
      reject(error)
    }
  }
}

module.exports = Promise;